package com.crcc.common.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;

import org.apache.commons.codec.binary.Base64;

import com.alibaba.fastjson.JSONObject;

/**
 * @Title:  RSAUtil ras加密解密加签解签工具类
 */
public class RSAUtil {
	
    private static final String KEY_ALGORITHM = "RSA";
    private static final int KEY_SIZE = 2048;//密钥长度
    private static final int ENCRYPT_SPLIT_LENGTH = 245;
    private static final int DECRYPT_SPLIT_LENGTH = 256;
    
    /**
     * @Title: init
     * @Description: 生成RSA秘钥对
     * @author wcl
     * @return  Map 秘钥对
     * @throw
     */
    public static Map<String, String> init() throws NoSuchAlgorithmException {
        HashMap<String, String> map = new HashMap<String, String>();//创建数据集合
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        keyPairGen.initialize(KEY_SIZE);//密钥生成 设置密钥长度
        KeyPair keyPair = keyPairGen.generateKeyPair();//创建密钥对
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();//获取公钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();//获取私钥
        map.put("public", Base64.encodeBase64String(publicKey.getEncoded()));//在数据集中加入公钥
        map.put("private", Base64.encodeBase64String(privateKey.getEncoded()));//在数据集中加入私钥
        System.out.println("公钥："+ Base64.encodeBase64String(publicKey.getEncoded()));//输出base64位的公钥
        System.out.println("私钥："+ Base64.encodeBase64String(privateKey.getEncoded()));//输出base64位的私钥
        return map;
    }
    
    /**
     * @Title: handleMultiArrays
     * @Description: 加密解密最大长度有限，要拆分处理
     * @author wcl
     * @param  src 待处理字节数组
     * @param  cipher 秘钥生成cipher
     * @param  splitLength 拆分长度
     * @return byte
     */
    private static byte[] handleMultiArrays(byte[] src,Cipher cipher,int splitLength) throws BadPaddingException, IllegalBlockSizeException, IOException {
        boolean flag = false;//是否大于最大长度状态
        ByteArrayOutputStream outputStream = null;//字节流
        try{
            outputStream = new ByteArrayOutputStream();
            int mol = src.length % splitLength;//取余
            int len = src.length / splitLength;//取整
            //是否 能整除
            if(mol==0){
                flag = true;
            }
            //循环加密
            for(int i=0;i<len;i++){
                byte[] tmp = cipher.doFinal(src,splitLength*i,splitLength);
                outputStream.write(tmp);//将byte放入ByteArrayOutputStream
            }
            //如果不能整除 将余出的数据加密
            if(!flag){
                byte[] tmp = cipher.doFinal(src,splitLength*len,src.length-splitLength*len);
                outputStream.write(tmp);
            }
            return outputStream.toByteArray();
        }finally {
            if(outputStream!=null) {
                outputStream.close();
            }
        }
    }

    /**
     * @Title:  decryptByPublicKey
     * @Description: 公钥加密
     * @author wcl
     * @param  dataStr 待加密数据
     * @param  keyStr 私钥
     * @return  byte[]
     */
    public static String encryptByPublicKey(String dataStr, String keyStr) throws Exception {
        byte [] key = Base64.decodeBase64(keyStr);
        byte [] data =dataStr.getBytes();
        //取得私钥
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        //产生公钥
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        //数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] retrunByte=handleMultiArrays(data,cipher,ENCRYPT_SPLIT_LENGTH);
        return Base64.encodeBase64String(retrunByte);

    }

    public static String encryptByPublicKeyForJS(String dataStr, String keyStr) throws Exception {
        byte [] key = Base64.decodeBase64(keyStr);
        byte [] data =dataStr.getBytes();
        //取得私钥
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        //产生公钥
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        //数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] retrunByte=cipher.doFinal(data);
        return Base64.encodeBase64String(retrunByte);

    }
    /**
     * @Title:  decryptByPrivateKey
     * @Description: 私钥解密
     * @author wcl
     * @param dataStr 待解密数据
     * @param keyStr  密钥
     * @return byte[] 解密数据
     * @throw
     */
    public static String decryptByPrivateKey(String dataStr, String keyStr) throws Exception {
        byte [] key = Base64.decodeBase64(keyStr);
        byte [] data = Base64.decodeBase64(dataStr);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        //数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return new String(handleMultiArrays(data,cipher,DECRYPT_SPLIT_LENGTH));
    }

    /**
     * @Title:  signByPrivateKey
     * @Description: 私钥加签
     * @author wcl
     * @param mySig 加签算法
     * @param privateStr  私钥串
     * @param data  需要签名的数据
     * @return byte[] 数据证书
     * @throw
     */
    public static String signByPrivateKey(Signature mySig,String privateStr,String data) throws Exception {
        String privateInfo="";
        byte[] byteData=data.getBytes();
        try {
            byte [] key = Base64.decodeBase64(privateStr);
            //取得私钥
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            //生成私钥
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

            mySig.initSign(privateKey);  //用私钥初始化签名对象
            mySig.update(byteData);  //将待签名的数据传送给签名对象
            privateInfo = Base64.encodeBase64String(mySig.sign());  //返回签名结果字节数组
        } catch (Exception e) {
            e.printStackTrace();
        }
        return privateInfo;
    }

    /**公钥验证签名
     * @param mySig 解签算法
     * @param publicStr 公钥串
     * @param infomation  需要解签的数据
     * @param publicInfo 私钥签名后的数据
     * @return
     * @author wcl
     */
    public static boolean unsignBypublic(Signature mySig,String publicStr,String infomation,String publicInfo){
        boolean verify=false;
        byte[] bytePublicInfo= Base64.decodeBase64(publicInfo);
        try {
            byte [] key = Base64.decodeBase64(publicStr);
            //实例化密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            //初始化公钥
            //密钥材料转换
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
            //产生公钥
            PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);

            mySig.initVerify(publicKey);  //使用公钥初始化签名对象,用于验证签名
            mySig.update(infomation.getBytes()); //更新签名内容
            verify= mySig.verify(bytePublicInfo); //得到验证结果
        } catch (Exception e) {
            e.printStackTrace();
        }
        return verify;
    }

    /**
     * @Title:  decryptByPrivateForJs
     * @Description: 私钥解密针对js
     * @author wcl
     * @param  dataStr 待加密数据
     * @param  privateKey 私钥
     * @return  byte[]
     */
    public static String decryptByPrivateForJs(String dataStr,String privateKey) {
        try {
            byte [] data = Base64.decodeBase64(dataStr);
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64 (privateKey));
            //实例化密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey key = keyFactory.generatePrivate(pkcs8KeySpec);
            //数据解密
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] bytes=cipher.doFinal(data);
            return new String (bytes);
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws Exception {

        Map<String, String> map = init();//生成密钥对
//        String publicKey =  map.get("public");
//        String privateKey = map.get("private");
//        System.out.println (publicKey.length());
//        System.out.println (privateKey.length());
//        String str = "上的尽快反馈及时反馈的司法考试发挥科技123阿斯蒂芬asd";
        /*******************************公钥加密私钥解密***********************************/
//        String publicData = encryptByPublicKey(str,publicKey);//公钥加密
//        System.out.println("公钥加密后数据："+ publicData);
//        System.out.println("私钥解密："+decryptByPrivateKey(publicData,privateKey));
//        System.out.println("***********************************************************");
        /*******************************js公钥加密java私钥解密*********************************/
//        String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgvEVsfkCFJhYZLT0gaB99OS7UirZ5fYI5dkeOs6s1iBhm+hwECRcJ9EajRtYGrDnwGcAMd3OVoArQ4RcQQuFfqhsam4OBioAQTrYsVQD7WnRKdMAhhhwREUpAP9Y+1IeBCXrQ99SDNO9zSWKTvPrybcKK3p1ErT0wsvPL5jl7zNsShTBYf3nigp5WGQxHpJBflGNg95EDy/RqtCnmW/OnCYFQ4euyGKkn7Nn+sSBhczffARF7a4SNufsL+tNAt5jXWRSHPnfdUwTCXPVal2aNkVgQXPkVvpjUqGQnVKRcA4r9ApdcpuDwQNgA1um+acjPIEI0M/o9YPu4uHJ3JKvVQIDAQAB";
//        String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDQQx0fJrHyfMUpZK27ZVX8PFSAsVrpDZHv2zZM/2YmIwBg3UAxL15+WCQ7Xiyd7W1bE9+lW5UrJo1Qq/qrIC8LL2LLgnmt/L0W8iKRQDgkrYO4GQGvgWWVLKTyTwXelhkq3gH64srKp+oLbiMQmLT0936/tr4ZJZ/yCNU61Bildr9q74gpvacf7RmCCXEKtzCyFVtizqePphzrDGQ7Cvx4lljOF1v56GNXaLqpeHKOKsLQ2DtJPPS20jYR7/g8NJqHQALfsDDhW7jBrwTnD2jBxT1SXXCo+HgXdDsj2CVPFYpalahupbVGrOTZc8VLGTUtNfpTmCM8X6bs1KHD18hnAgMBAAECggEAYfYfvaZq75/m8eiMm+g3wPTz3rEODS+35LYdXayI9QljxSxtZHVeoll9eXt7yzGCTeQUP+jLSsfQkxDCUTpLRpycgRO3frKykxeEUQR/JCmGGtOQamiYSsn8MIohPakm33YcQlHph9fiDExbLBRYkh3UvgMMejGrgaLMAecATNusI6JfpI8Vqnb2VAbyjRq/YLMykNDYQPdEbsrQ7Bhz2LNTnvFqT2ePE7M6mQv/Rb9GiVRJfShgNGNN6XxTIAXMixcAodYp2VSMnEVHvFkC3ldB7a2KFXDRvNxptRk3Pi1o6+B0aAPGZTAsH/9q7Yo0b34wdiE/UYxgZR2BhsLK6QKBgQDvUWGNRfTzdB/cjgSZoLIpiyAHfw2X7RtkDTcj2vEVBSl8AcQxcmbH2Hfm94S9HfB4o8TAjzEH2vn6aqGw/TWwX2y0wpZFig9KiD/d3Ddae/CskKHVqFSOQReP8VaHoxJo/QzDU8OB/FPJd2/LCqSBML3Ym3pdMKtutf0XIrXPcwKBgQDex4tYYaGaUkzFR0jw7MMDHu51LpLOEJzMKl1HsTtt8qOYHDJFMB69SutcM2Eqn7/QYOwG06RTIShG12DGhD0RhxbMIEiVmimPk4vV/HI7zYxZHAXVDwybChsCZcuDlaJ9uYDBF9v6GSgGerEVZBSnjHiH3Fvx62tB7SICl7q+PQKBgQDAq/lo/sh99KDuNZx4fwrRLYRE5MJx7WAfBhC9mjh8HuLORrHIyXz8KkgmOGKyy1beGaN/EAl+dIrLVGwHDWTbMYhYY00OgV9cNyOMIA6kl6IlnG/ejx48RSWOKtPqcZyR0CElZNvDW/2s9q6XfmMA69f8evhh7JwojvZLWROdBwKBgFfjg07P3ZBjTZQ6xkT+MwVFK7AhOpt/JEzLnddNzXNX2UCGRzLShB4Ls4TBZGELewH7asJatqZxG1GvYKeQvgLvN4g6aEhU9HaHMBCwsmRzeB4jlw1yDXgQ6YztmfeEjgFpsKj8/7TQPeEogDo/LILZQSfgQInVZZAxvEwnje3FAoGAenDMl1fk82zSu2lz6FLcCnIzknlSs3hSb/WcYgeNuX34Dos7S7oLAZBe0uj2ZtA7Ju0V0VdFlfGruAPERoAYcddMcKKI+gUbBbifTCbk5yauVJo8hJq6nzVZBCHGrChRfmgo95p5fVy+7PVB9YbvJChDmGKjlSoG8TuUDxvxxAM=";
//        String publicData = encryptByPublicKeyForJS(str,publicKey);//公钥加密
//        System.out.println("公钥加密后数据："+ publicData);
//        System.out.println("私钥解密："+decryptByPrivateForJs(publicData,privateKey));
//        System.out.println("***********************************************************");


    }
}
